﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xunit;
using Moq;

namespace MvcWiki.Test.Service.WikiPageService
{
    public class DeleteWikiPageFacts
    {
        [Fact]
        public void Call()
        {
            var wikiPage = new MvcWiki.Model.WikiPage { Namespace = new MvcWiki.Model.WikiNamespace() };

            var wikiPageRepository = new Mock<MvcWiki.Repository.IWikiPageRepository>();
            wikiPageRepository.Setup(x => x.GetWikiPage("Namespace", "Page")).Returns(wikiPage);

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiPageRepository()).Returns(wikiPageRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var wikiUserProvider = new Mock<MvcWiki.User.IWikiUserProvider>();
            wikiUserProvider.Setup(x => x.CanEditNamespace(It.IsAny<MvcWiki.Model.WikiNamespace>())).Returns(true);
            wikiUserProvider.Setup(x => x.CanDeletePage(wikiPage)).Returns(true);

            var service = new MvcWiki.Service.WikiPageService(repositoryFactory.Object, unitOfWork.Object, wikiUserProvider.Object);

            service.DeleteWikiPage("Namespace", "Page");
        }

        [Fact]
        public void Calls_IWikiPageRepository_GetWikiPage()
        {
            var wikiPage = new MvcWiki.Model.WikiPage { Namespace = new MvcWiki.Model.WikiNamespace() };

            var wikiPageRepository = new Mock<MvcWiki.Repository.IWikiPageRepository>();
            wikiPageRepository.Setup(x => x.GetWikiPage("Namespace", "Page")).Returns(wikiPage);

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiPageRepository()).Returns(wikiPageRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var wikiUserProvider = new Mock<MvcWiki.User.IWikiUserProvider>();
            wikiUserProvider.Setup(x => x.CanEditNamespace(It.IsAny<MvcWiki.Model.WikiNamespace>())).Returns(true);
            wikiUserProvider.Setup(x => x.CanDeletePage(wikiPage)).Returns(true);

            var service = new MvcWiki.Service.WikiPageService(repositoryFactory.Object, unitOfWork.Object, wikiUserProvider.Object);

            service.DeleteWikiPage("Namespace", "Page");

            wikiPageRepository.Verify(x => x.GetWikiPage("Namespace", "Page"));
        }

        [Fact]
        public void Calls_IWikiPageRepository_DeleteWikiPage()
        {
            var wikiPage = new MvcWiki.Model.WikiPage { Namespace = new MvcWiki.Model.WikiNamespace() };

            var wikiPageRepository = new Mock<MvcWiki.Repository.IWikiPageRepository>();
            wikiPageRepository.Setup(x => x.GetWikiPage("Namespace", "Page")).Returns(wikiPage);

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiPageRepository()).Returns(wikiPageRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var wikiUserProvider = new Mock<MvcWiki.User.IWikiUserProvider>();
            wikiUserProvider.Setup(x => x.CanEditNamespace(It.IsAny<MvcWiki.Model.WikiNamespace>())).Returns(true);
            wikiUserProvider.Setup(x => x.CanDeletePage(wikiPage)).Returns(true);

            var service = new MvcWiki.Service.WikiPageService(repositoryFactory.Object, unitOfWork.Object, wikiUserProvider.Object);

            service.DeleteWikiPage("Namespace", "Page");

            wikiPageRepository.Verify(x => x.DeleteWikiPage(It.IsAny<MvcWiki.Model.WikiPage>()));
        }

        [Fact]
        public void Calls_IWikiPageRepository_DeleteWikiPage_With_WikiPage_Returned_From_GetWikiPage()
        {
            var wikiPage = new MvcWiki.Model.WikiPage { Namespace = new MvcWiki.Model.WikiNamespace() };

            var wikiPageRepository = new Mock<MvcWiki.Repository.IWikiPageRepository>();
            wikiPageRepository.Setup(x => x.GetWikiPage("Namespace", "Page")).Returns(wikiPage);

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiPageRepository()).Returns(wikiPageRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var wikiUserProvider = new Mock<MvcWiki.User.IWikiUserProvider>();
            wikiUserProvider.Setup(x => x.CanEditNamespace(It.IsAny<MvcWiki.Model.WikiNamespace>())).Returns(true);
            wikiUserProvider.Setup(x => x.CanDeletePage(wikiPage)).Returns(true);

            var service = new MvcWiki.Service.WikiPageService(repositoryFactory.Object, unitOfWork.Object, wikiUserProvider.Object);

            service.DeleteWikiPage("Namespace", "Page");

            wikiPageRepository.Verify(x => x.DeleteWikiPage(wikiPage));
        }

        [Fact]
        public void Calls_IUnitOfWork_Commit()
        {
            var wikiPage = new MvcWiki.Model.WikiPage { Namespace = new MvcWiki.Model.WikiNamespace() };

            var wikiPageRepository = new Mock<MvcWiki.Repository.IWikiPageRepository>();
            wikiPageRepository.Setup(x => x.GetWikiPage("Namespace", "Page")).Returns(wikiPage);

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiPageRepository()).Returns(wikiPageRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var wikiUserProvider = new Mock<MvcWiki.User.IWikiUserProvider>();
            wikiUserProvider.Setup(x => x.CanEditNamespace(It.IsAny<MvcWiki.Model.WikiNamespace>())).Returns(true);
            wikiUserProvider.Setup(x => x.CanDeletePage(wikiPage)).Returns(true);

            var service = new MvcWiki.Service.WikiPageService(repositoryFactory.Object, unitOfWork.Object, wikiUserProvider.Object);

            service.DeleteWikiPage("Namespace", "Page");

            unitOfWork.Verify(x => x.Commit());
        }

        [Fact]
        public void Calls_WikiUserProvider_CanEditNamespace()
        {
            var wikiPage = new MvcWiki.Model.WikiPage { Namespace = new MvcWiki.Model.WikiNamespace() };

            var wikiPageRepository = new Mock<MvcWiki.Repository.IWikiPageRepository>();
            wikiPageRepository.Setup(x => x.GetWikiPage("Namespace", "Page")).Returns(wikiPage);

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiPageRepository()).Returns(wikiPageRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var wikiUserProvider = new Mock<MvcWiki.User.IWikiUserProvider>();
            wikiUserProvider.Setup(x => x.CanEditNamespace(It.IsAny<MvcWiki.Model.WikiNamespace>())).Returns(true);
            wikiUserProvider.Setup(x => x.CanDeletePage(wikiPage)).Returns(true);

            var service = new MvcWiki.Service.WikiPageService(repositoryFactory.Object, unitOfWork.Object, wikiUserProvider.Object);

            service.DeleteWikiPage("Namespace", "Page");

            wikiUserProvider.Verify(x => x.CanEditNamespace(It.IsAny<MvcWiki.Model.WikiNamespace>()));
        }

        [Fact]
        public void Throws_Exception_If_CanEditNamespace_Is_False()
        {
            var wikiPage = new MvcWiki.Model.WikiPage { Namespace = new MvcWiki.Model.WikiNamespace() };

            var wikiPageRepository = new Mock<MvcWiki.Repository.IWikiPageRepository>();
            wikiPageRepository.Setup(x => x.GetWikiPage("Namespace", "Page")).Returns(wikiPage);

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiPageRepository()).Returns(wikiPageRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var wikiUserProvider = new Mock<MvcWiki.User.IWikiUserProvider>();
            wikiUserProvider.Setup(x => x.CanEditNamespace(
                It.Is<MvcWiki.Model.WikiNamespace>(y => y.Name == "Namespace"))).Returns(false);
            wikiUserProvider.Setup(x => x.CanDeletePage(wikiPage)).Returns(true);

            var service = new MvcWiki.Service.WikiPageService(repositoryFactory.Object, unitOfWork.Object, wikiUserProvider.Object);

            Assert.Throws<MvcWiki.Exceptions.AuthorizationException>(
                () => service.DeleteWikiPage("Namespace", "Page"));
        }

        [Fact]
        public void Calls_WikiUserProvider_CanDeletePage()
        {
            var wikiPage = new MvcWiki.Model.WikiPage { Namespace = new MvcWiki.Model.WikiNamespace() };

            var wikiPageRepository = new Mock<MvcWiki.Repository.IWikiPageRepository>();
            wikiPageRepository.Setup(x => x.GetWikiPage("Namespace", "Page")).Returns(wikiPage);

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiPageRepository()).Returns(wikiPageRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var wikiUserProvider = new Mock<MvcWiki.User.IWikiUserProvider>();
            wikiUserProvider.Setup(x => x.CanEditNamespace(It.IsAny<MvcWiki.Model.WikiNamespace>())).Returns(true);
            wikiUserProvider.Setup(x => x.CanDeletePage(wikiPage)).Returns(true);

            var service = new MvcWiki.Service.WikiPageService(repositoryFactory.Object, unitOfWork.Object, wikiUserProvider.Object);

            service.DeleteWikiPage("Namespace", "Page");

            wikiUserProvider.Verify(x => x.CanDeletePage(wikiPage));
        }

        [Fact]
        public void Throws_Exception_If_CanEditPage_Is_False()
        {
            var wikiPage = new MvcWiki.Model.WikiPage { Namespace = new MvcWiki.Model.WikiNamespace() };

            var wikiPageRepository = new Mock<MvcWiki.Repository.IWikiPageRepository>();
            wikiPageRepository.Setup(x => x.GetWikiPage("Namespace", "Page")).Returns(wikiPage);

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiPageRepository()).Returns(wikiPageRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var wikiUserProvider = new Mock<MvcWiki.User.IWikiUserProvider>();
            wikiUserProvider.Setup(x => x.CanEditNamespace(It.IsAny<MvcWiki.Model.WikiNamespace>())).Returns(true);
            wikiUserProvider.Setup(x => x.CanDeletePage(wikiPage)).Returns(false);

            var service = new MvcWiki.Service.WikiPageService(repositoryFactory.Object, unitOfWork.Object, wikiUserProvider.Object);

            Assert.Throws<MvcWiki.Exceptions.AuthorizationException>(
                () => service.DeleteWikiPage("Namespace", "Page"));
        }
    }
}
